#+-----------------------------------------------------------------------------
#|
#| FILENAME: bargraph.pm
#|
#| PROJECT: Perl Libraries
#|
#| FILE DESCRIPTION:
#|    This file contains an implementation of a bar graph.
#|
#+------------------------------------------------------------------------------
#|
#| Cairolib is a series of extensions, examples, and libraries for the
#| Cairo graphics package (see http://www.cairographics.org).
#| 
#| Copyright (C) 2006  Bradford Elliott
#|
#| This library is free software; you can redistribute it and/or
#| modify it under the terms of the GNU Lesser General Public
#| License as published by the Free Software Foundation; either
#| version 2.1 of the License, or (at your option) any later version.
#| 
#| This library is distributed in the hope that it will be useful,
#| but WITHOUT ANY WARRANTY; without even the implied warranty of
#| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#| Lesser General Public License for more details.
#| 
#| You should have received a copy of the GNU Lesser General Public
#| License along with this library; if not, write to the Free Software
#| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#| 
#+------------------------------------------------------------------------------
package cairolib::bargraph;

use strict;
use warnings;
use cairolib::graph;
use POSIX qw(ceil floor);

our @ISA = ('cairolib::graph');

#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    new()
#|
#| SYNOPSIS:
#|    new($width, $height);
#|
#| PARAMETERS:
#|    $width  (I) - The width of the graph to be created.
#|    $height (I) - The height of the graph to be created.
#|
#| FUNCTION:
#|    This is the constructor for the graph class which is used to construct
#|    a new graph object.
#|
#| RETURNS:
#|    Reference to the class object.
#|
#| NOTES:
#|    None.
#|
#+-----------------------------------------------------------------------------
sub new
{
    my $that = shift;
    my $class = ref($that) || $that;
    
    my $self= new cairolib::graph(@_);
    
    my $temp = undef;
    $self->{"TEMP"} = \$temp;
    
    bless($self, $class);
    
    $self->init();
    
    return $self;
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    DESTROY()
#|
#| SYNOPSIS:
#|    DESTROY()
#|
#| PARAMETERS:
#|    None.
#|
#| FUNCTION:
#|    This is the destructor for the graph class. It is called
#|    automatically by perl when the instance of the class is no longer
#|    required.
#|
#| RETURNS:
#|    None.
#|
#| NOTES:
#|    None.
#|
#+-----------------------------------------------------------------------------
sub DESTROY
{
    my $self = shift;
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    init()
#|
#| SYNOPSIS:
#|    init()
#|
#| PARAMETERS:
#|    None.
#|
#| FUNCTION:
#|    This is the main initializer for the graph class.
#|
#| RETURNS:
#|    None.
#|
#| NOTES:
#|    None.
#|
#+-----------------------------------------------------------------------------
sub init
{
    my $self = shift;
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    ()
#|
#| PARAMETERS:
#|    
#|
#| FUNCTION:
#|    
#|
#| RETURNS:
#|    
#|
#+-----------------------------------------------------------------------------
sub drawXAxis
{
    my $self = shift;
    
    my $maxX = $self->getMaxXCoordiate();
    my $maxY = $self->getMaxYCoordinate();
    
    my $graph = $self->{GRAPH};
    
    my $height = ${$self->{HEIGHT}};
    my $width = ${$self->{WIDTH}};
    my $top = ${$self->{TOP}};
    my $left = ${$self->{LEFT}};
    my $right = ${$self->{RIGHT}};
    my $bottom = ${$self->{BOTTOM}};
    
    my $increment = $maxX/10.0;
    
    if(1 == $self->{XAXIS}{"autoscale"})
    {
        my $increment = ceil($maxX/10);
    }
    
    my $xAxisIncrements = $maxX/$increment;
    
    # Draw the X-Axis
    for(my $count = 0; $count < $xAxisIncrements + 1; $count++)
    {
        my $horizontalPosition = $left + ($count * ($width/$xAxisIncrements));
        
        if($count != $xAxisIncrements && $count != 0)
        {
            $graph->drawLine({"x1" => $horizontalPosition,
                              "y1" => $top,
                              "x2" => $horizontalPosition,
                              "y2" => $bottom,
                              "line-color" => "#000000",
                              "line-weight" => 0.5,
                              "line-pattern" => 2,
                              "background-color" => "#FFFFFF"});
            
            $graph->drawLine({"x1" => $horizontalPosition,
                              "y1" => $bottom - 5,
                              "x2" => $horizontalPosition,
                              "y2" => $bottom + 5,
                              "line-color" => "#000000",
                              "background-color" => "#FFFFFF"});
        }
    
        my $label;
        if(0)
        {
            $label = ceil(($count * $maxX * $increment)/($maxX));
        }
        else
        {
            $label = ($count * $maxX * $increment)/($maxX);
        }
       
        $graph->drawText({"x" => $horizontalPosition - 3,
                          "y" => $bottom + 25,
                          "line-color" => "#000000",
                          "background-color" => "#FFFFFF",
                          "text" => $label});
    }
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    ()
#|
#| PARAMETERS:
#|    
#|
#| FUNCTION:
#|    
#|
#| RETURNS:
#|    
#|
#+-----------------------------------------------------------------------------
sub drawYAxis
{
    my $self = shift;
    
    my $maxX = $self->getMaxXCoordiate();
    my $maxY = $self->getMaxYCoordinate();
    
    my $graph = $self->{GRAPH};
    
    my $increment = ceil($maxY/10);
    my $yAxisIncrements = $maxY/$increment;
    my $height = ${$self->{HEIGHT}};
    my $width = ${$self->{WIDTH}};
    my $top = ${$self->{TOP}};
    my $left = ${$self->{LEFT}};
    my $right = ${$self->{RIGHT}};
    my $bottom = ${$self->{BOTTOM}};
    
    # Draw the Y-Axis
    for(my $count = 0; $count < $yAxisIncrements + 1; $count++)
    {
        my $verticalPosition = $top + ($count * ($height/$yAxisIncrements));
        
        if($count != $yAxisIncrements && $count != 0)
        {
            $graph->drawLine({"x1" => $left,
                              "y1" => $verticalPosition,
                              "x2" => $right,
                              "y2" => $verticalPosition,
                              "line-color" => "#000000",
                              "line-weight" => 0.5,
                              "line-pattern" => 2,
                              "background-color" => "#FFFFFF"});
            
            $graph->drawLine({"x1" => $left - 5,
                              "y1" => $verticalPosition,
                              "x2" => $left + 5,
                              "y2" => $verticalPosition,
                              "line-color" => "#000000",
                              "background-color" => "#FFFFFF"});
        }
       
        my $label = $maxY - ceil(($count * $maxY * $increment)/($maxY));
        
        $graph->drawText({"x" => $left - 25, 
                          "y" => $verticalPosition + 4,
                          "line-color" => "#000000",
                          "background-color" => "#FFFFFF",
                          "text" => $label});
    }
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    ()
#|
#| PARAMETERS:
#|    
#|
#| FUNCTION:
#|    
#|
#| RETURNS:
#|    
#|
#+-----------------------------------------------------------------------------
sub drawData
{
    my $self = shift;
    my $maxX = $self->getMaxXCoordiate();
    my $maxY = $self->getMaxYCoordinate();
    my $graph = $self->{GRAPH};
    
    my $yincrement = ceil($maxY/10);
    
    my $xincrement;
    if(1 == $self->{XAXIS}{"autoscale"})
    {
        $xincrement = ceil($maxX/10);
    }
    else
    {
        $xincrement = $maxX/10;
    }
    
    my $yAxisIncrements = $maxY/$yincrement;
    my $xAxisIncrements = $maxX/$xincrement;
    my $height = ${$self->{HEIGHT}};
    my $width = ${$self->{WIDTH}};
    my $top = ${$self->{TOP}};
    my $left = ${$self->{LEFT}};
    my $right = ${$self->{RIGHT}};
    my $bottom = ${$self->{BOTTOM}};
    my $numdatasets = keys(%{$self->{DATASETS}});
    
    my $offset = 0;
    foreach my $dataset (keys(%{$self->{DATASETS}}))
    {
        my $prevx = $left;
        my $prevy = $bottom;
        my $color = $self->{DATASETS}{$dataset}{"color"};
        my $barwidth= 0;
        my $barheight = 0;
        
        foreach my $key (sort {$a <=> $b} keys(%{$self->{DATASETS}{$dataset}{"data"}}))
        {
            # Need to round to the whole number because
            # plotting fractions on a bar graph don't make sense
            my $xvalue = sprintf("%.0f", $key);
            my $yvalue = $self->{DATASETS}{$dataset}{"data"}{$key};
            
            my $x = ((($xvalue/$xincrement)/10.0) * $width) + $left + $offset;
            my $y = $bottom - ((($yvalue/$yincrement)/10.0) * $height);
            
            $barheight = $bottom - $y;
            $barwidth  = ($right - $left - 30)/($xAxisIncrements * $numdatasets);
            
            $graph->drawRect({"x" => $x,
                              "y" => $y,
                              "width" => $barwidth,
                              "height" => $barheight,
                              "line-color" => "#000000",
                              "background-color" => $color});
            
            $prevx = $x;
            $prevy = $y;
        }
        $offset += $barwidth;
    }
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    ()
#|
#| PARAMETERS:
#|    
#|
#| FUNCTION:
#|    
#|
#| RETURNS:
#|    
#|
#+-----------------------------------------------------------------------------
sub drawGraph
{
    my $self = shift;
    my $output = $_[0];
    
    $self->SUPER::drawGraph();
    
    my $graph = $self->{GRAPH};
    
    $self->drawYAxis();
    $self->drawXAxis();
    $self->drawData();
    
    return $graph->create($output);
}


1